/* Copyright 2024 Coremail
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import type {
  Filter,
  FolderData,
  IBuffer,
  IBufferCreator,
  IMailStorage,
  IStore,
  MailBasic,
  Order,
  Properties,
  Query
} from 'coremail';
import {
  CMError,
  ErrorCode,
  FolderType,
  MailAttribute,
  StoreFeature,
  getLogger,
  ImapStore,
  Pop3Store,
  delay,
  EventHandler,
  memBufferCreator,
} from 'coremail';
import util from '@ohos.util';
import promptAction from '@ohos.promptAction';

const logger = getLogger("mem_store");
const countLogger = getLogger("__unreadCount");
// 使用正常无法使用的字符串来作为虚拟文件夹的名字
export const IMPORTANT_FOLDER_NAME = "<<~!@#$%^&*()_+>"
export const IMPORTANT_FOLDER_DISPLAY_NAME = "重要邮件"
export const DRAFT_DISPLAY_NAME = "草稿箱"
const UNREAD_FOLDER_NAME = "$$unread$$"

const FETCH_COUNT = 15;
const INBOX = 'INBOX'
const SYNC_INTERVAL = "sync-interval"


const DEFAULT_FOLDER_LIST: FolderData[] = [
  {
    name: INBOX, fullName: INBOX, parent: "", type: FolderType.inbox,
    mailCount: 0, unreadCount: 0, recent: 0,
  },
  {
    name: 'sent', fullName: 'sent', parent: "", type: FolderType.sent,
    mailCount: 0, unreadCount: 0, recent: 0,
  },
  {
    name: 'draft', fullName: 'draft', parent: "", type: FolderType.draft,
    mailCount: 0, unreadCount: 0, recent: 0,
  },
  {
    name: 'trash', fullName: 'trash', parent: "", type: FolderType.trash,
    mailCount: 0, unreadCount: 0, recent: 0,
  },
]


/*
 * 带同步机制的Store，依赖IMailStorage的对象来实现本地存储。
 */
export class SyncStore implements IStore {
  _properties?: Properties;
  _folderReady = false;
  _mailReady = false;
  _store?: IStore;
  _currentFolder: string = "";
  _events = new EventHandler();
  _syncPromise?: Promise<void>;
  _storage: IMailStorage;
  _folderList: FolderData[] = [];

  _storeCloseTimer?: number;
  _storeCloseTimeout = 15 * 1000;
  _bufferCreator: IBufferCreator = memBufferCreator;

  constructor(storage: IMailStorage) {
    this._storage = storage;
  }

  setBufferCreator(creator: IBufferCreator): void {
    this._bufferCreator = creator;
  }

  createStore(properties: Properties): IStore {
    let store: IStore;
    if (properties.imap) {
      store = new ImapStore();
    } else if (properties.pop3) {
      store = new Pop3Store();
    } else {
      throw new CMError("imap and pop3 must specify at least one",
        ErrorCode.PARAMETER_ERROR);
    }
    store.setProperties(properties);
    store.setBufferCreator(this._bufferCreator);
    return store;
  }
  setProperties(properties: Properties): void {
    this._properties = properties;
    // this._store = this.createStore(properties);
    // this.sync();
  }

  /**
   * 释放资源
   */
  release():Promise<void> {
    return this._storage.release();
  }

  addImportantFolder(folderDataList: FolderData[]): FolderData[] {
    return [
      ...folderDataList, {
        name: IMPORTANT_FOLDER_NAME,
        fullName: IMPORTANT_FOLDER_NAME,
        parent: "",
        type: FolderType.important,
        mailCount: 0,
        unreadCount: 0,
        recent: 0
      }
    ]
  }
  async syncFolder(store: IStore): Promise<FolderData[]> {
    const folderDataList = await store.getAllFolderList();
    for (const fd of folderDataList!) {
      const fdNew: FolderData | null = await store.getFolderInfo(fd.fullName).catch((err: unknown): null => {
        logger.error("get folder info failed", fd.fullName, err);
        return null;
      });
      if (!fdNew) {
        continue;
      }
      fd.mailCount = fdNew.mailCount;
      fd.unreadCount = fdNew.unreadCount;
      fd.recent = fdNew.recent;
    }
    // 加上虚拟文件夹
    this._folderList = this.addImportantFolder(folderDataList);
    await this._storage.setFolderList(folderDataList).then(() => {
      this._folderReady = true;
    }).catch((err: unknown) => {
      logger.error("save folder list to storage failed", err)
    });
    return folderDataList;
  }

  /*
  * 同步策略：每个文件夹每次最多同步 FETCH_COUNT = 15 封邮件
  * 根据底层 IStore 支持能力，imap先同步邮件基本信息，再同步邮件整体内容，
  * pop3只能整封邮件同步下来
   */
  async syncFolderMail(store: IStore, folderDataList: FolderData[]): Promise<void> {
    logger.debug("syncFolderMail", folderDataList);
    let finish = false;
    let folderSyncNumber: Map<string, number> = new Map();
    for (const fd of folderDataList) {
      folderSyncNumber.set(fd.fullName, fd.mailCount ?? 0);
    }
    let folderMailids:Map<string,string[]> = new Map();
    while (!finish) {
      finish = true;
      for (const fd of folderDataList) {
        let end = folderSyncNumber.get(fd.fullName)!;
        if (end <= 0) {
          continue;
        }
        logger.debug("syncFolderMail", end);
        let start = end + 1 - FETCH_COUNT;
        let count = FETCH_COUNT;
        if (start <= 0) {
          count = count + start - 1;
          start = 1;
        }
        end = start - 1;
        folderSyncNumber.set(fd.fullName, end);
        if (end > 0) {
          finish = false;
        }
        let mailids = await this.syncOneFolderMail(store, fd.fullName, start, count)
        if (start + count >= fd.mailCount) { // 发送一次就好
          this._events.emit(SYNC_INTERVAL, fd.fullName);
        }
        this.addMailsToFolderMails(folderMailids,fd.fullName,mailids);
      }
    }
    //删除只有本地有,远程没有的数据.
    await this.deleteDbOnlyMails(folderDataList,folderMailids);
    logger.debug("syncFolderMail end");
  }

  //删除仅存在于db的数据
  async deleteDbOnlyMails(folderDataList:FolderData[],folderMailIds:Map<string,string[]>) {
    for (const fd of folderDataList) {
      let remoteFolderMailsIds:string[] = folderMailIds.get(fd.fullName) ?? [];
      let dbFolderMailsIds:string[] = await this._storage.getFolderMailIdList(fd.fullName,0,0,{by:"date",desc:true})
      let dbOnlyMails:string[] = this.groupMinus(dbFolderMailsIds,remoteFolderMailsIds);
      for(let mailId of dbOnlyMails) {
        //删除数据库
        await this._storage.deleteMail(fd.fullName,mailId);
        //删除ui
        let param = {
          folderFullName:fd.fullName,
          mailId:mailId,
        }
        this._events.emit("delete-mail", param);
      }
    }
  }


  /**
   * 从集合a中减去集合b的数据,返回只有集合a有,但是集合b没有的数据.
   * @param a
   * @param b
   */
  groupMinus(a:string[],b:string[]):string[] {
    return a.filter((item)=>(!b.includes(item)))
  }


  addMailsToFolderMails(map:Map<string,string[]>,key:string,mails:string[]) {
    let arr:string[] = map.get(key);
    if(!arr) {
      arr = [];
      map.set(key,arr);
    }
    arr.push(...mails);
  }


  async syncOneFolderMail(store: IStore, folderFullName: string, start: number, count: number):Promise<string[]> {
    const fullName = folderFullName;
    logger.debug("sync mail", fullName, start, count);
    await store.openFolder(fullName);
    const list = await store
      .getFolderMailIdList(fullName, start, count, { by: "date", desc: true, })
      .catch(err => {
        logger.error("get mail list failed", fullName, start, count, err);
      });
    if (!list || list.length == 0) {
      return [];
    }
    const headerFailedMailIdList: string[] = [];
    if (store.hasFeature(StoreFeature.MailPart)) {
      const mailList: MailBasic[] = [];
      const newMailIdList: string[] = [];
      const updateMailIdList: Map<string,MailAttribute[]> = new Map();
      for (const mailId of list) {
        const mailBasic: MailBasic | null = await store.getMailBasic(fullName, mailId).catch((err: unknown): null => {
          logger.error('sync mail basic', folderFullName, mailId, err);
          return null;
        });
        if (!mailBasic) {
          headerFailedMailIdList.push(mailId);
          continue;
        }
        mailList.push(mailBasic);
        if (await this._storage.hasMail(fullName, mailId)) {
          updateMailIdList.set(mailId,mailBasic.attributes);
        }
        else {
          newMailIdList.push(mailId);
        }
      }
      if (mailList.length > 0) {
        logger.trace("sync add basic")
        await this._storage.addMailBasicList(fullName, mailList);
      }
      for (const mailId of headerFailedMailIdList) {
        // 对于拿邮件头失败的邮件，尝试整封邮件拿下来。
        try {
          const mail = await store.getMail(fullName, mailId);
          let needUpdateNotify = false;
          if (await this._storage.hasMail(fullName, mailId)) {
            needUpdateNotify = true;
          }
          else {
            newMailIdList.push(mailId);
          }
          await this._storage.addMail(fullName, mailId, mail);
          if(needUpdateNotify) {
            let mailBasic = await this._storage.getMailBasic(fullName,mailId);
            updateMailIdList.set(mailId,mailBasic.attributes);
          }
        } catch (err: unknown) {
          logger.error("sync mail full", folderFullName, mailId, err);
        }
      }
      if(updateMailIdList.size > 0) {
        let param = {
          folderFullName: fullName,
          map: updateMailIdList
        }
        this._events.emit("update-mail", param);
      }
      if (fullName.toLowerCase() == "inbox" && newMailIdList.length > 0) {
        this._events.emit("new-mail", fullName, newMailIdList);
      }
    } else { // pop3 只能整份邮件同步下来
      const newMailIdList: string[] = [];
      for (const mailId of list) {
        logger.debug("sync mail", mailId);
        if (await this._storage.hasMail("*", mailId)) {
          logger.debug("sync mail has mail", mailId);
          continue;
        }
        const mail = await store.getMail(fullName, mailId).catch((err: CMError) => {
          logger.error('sync full mail failed', folderFullName, mailId, err);
        });
        if (!mail) {
          continue;
        }
        logger.debug("sync mail start", mailId);
        try {
          await this._storage.addMail(fullName, mailId, mail);
          //pop3对于新同步下来的邮件视为未读的.
          await this._storage.setMailAttributes(mailId, fullName, [
            MailAttribute.Seen
          ], "-");
          logger.debug("sync mail end", mailId);
          newMailIdList.push(mailId);
        } catch (e: unknown) {
          logger.error("sync mail failed", mailId)
        }
      }
      if (fullName.toLowerCase() == "inbox" && newMailIdList.length > 0) {
        this._events.emit("new-mail", fullName, newMailIdList);
      }
      logger.debug("sync mail end ====");
    }
    return list;``
  }

  getStore(autoRelease = true): IStore {
    return this.createStore(this._properties);
    /*
    if (this._storeCloseTimer) {
      clearTimeout(this._storeCloseTimer);
      if (autoRelease) {
        this._storeCloseTimer = setTimeout(() => {
          this.releaseStore();
        }, this._storeCloseTimeout);
      }
    }
    if (!this._store) {
      this._store = this.createStore(this._properties);
    }
    return this._store;
    */
  }

  releaseStore(): void {
    this._store?.release();
  }

  async sync(): Promise<void> {
    countLogger.debug("==start sync==", this._syncPromise);
    if (!this._syncPromise) {
      this._syncPromise = (async (): Promise<void> => {
        logger.debug("sync promise")
        let store = this.getStore();
        const canSync = store.check().then(() => true).catch(e => false)
        if (!canSync) {
          store.release();
          return;
        }
        if (store.hasFeature(StoreFeature.Folder)) { // imap
          try {
            const folderDataList = await this.syncFolder(store);
            await this.syncFolderMail(store, folderDataList);
          } catch (e: unknown) {
            logger.error('sync imap failed', e);
          }
          store.release();
        } else { // pop3
          // store = this.createStore(this._properties!);
          try {
            await this.initFolders();
            const fd = await store.getFolderInfo(INBOX).catch(e => {
              logger.error("pop3 get folder info failed", e);
            });
            if (!fd) {
              return;
            }
            if (fd.mailCount < FETCH_COUNT) {
              await this.syncOneFolderMail(store, INBOX, 1, fd.mailCount);
              this._events.emit(SYNC_INTERVAL, INBOX);
            }
            else { // 邮件较多，先同步最新的。
              await this.syncOneFolderMail(
                store,
                INBOX,
                fd.mailCount - FETCH_COUNT + 1,
                FETCH_COUNT);
              this._events.emit(SYNC_INTERVAL, INBOX);
              await this.syncOneFolderMail(store, INBOX, 1, fd.mailCount - FETCH_COUNT);
            }
          } catch(e: unknown) {
            logger.error('sync imap failed', e);
          }
          store.release();
        }
        countLogger.debug("==end sync==");
        this._events.emit("sync-end");
        this._syncPromise = undefined;
        this._mailReady = true;
      })();
    }
    try {
      await this._syncPromise;
    } catch (e) {
      this._syncPromise = undefined;
      if (e as CMError && (e as CMError).code == ErrorCode.LOGIN_FAILED) {
        promptAction.showToast({ message: "账号或密码错误"})
      }
      logger.error("sync failed", e);
    }
    return this._syncPromise;
  }

  async initFolders(): Promise<void> {
    let folderList = await this._storage.getFolderList();
    // await this.getStore().getFolderInfo(INBOX);
    if (!folderList || folderList.length == 0) { // 还未同步过文件夹
      folderList = DEFAULT_FOLDER_LIST;
      this._storage.setFolderList(folderList);
    }
    this._folderList = this.addImportantFolder(folderList);
    this._folderReady = true;
  }

  async waitSomeTimeForInit(): Promise<void> {
    const waitTimes = 10;
    for (let i = 0; i < waitTimes; i++) {
      // 还未同步完，先等一会
      await delay(500);
    }
  }

  async getFolderMailIdList(
    folderFullName: string,
    start: number,
    size: number,
    order: Order
  ): Promise<string[]> {
    let mailList: string[] = [];
    mailList = await this._storage.getFolderMailIdList(folderFullName, start, size, order).catch(err => {
      logger.error(`get ${folderFullName} mail list ${start} ${size} from storage failed`, err)
      return [];
    });
    return mailList;
  }

  async getAllFolderList(): Promise<FolderData[]> {
    if (!this._folderReady) {
      const store = this.getStore();
      if (store.hasFeature(StoreFeature.Folder)) {
        if (this._folderList.length > 0) {
          return this._folderList;
        }
        let folderDataList: FolderData[] = await this.syncFolder(store).catch((err: unknown) => {
          logger.error("syn folder failed")
          return [];
        });
        if (!folderDataList || folderDataList.length == 0) {
          folderDataList = await this._storage.getFolderList();
          this._folderList = this.addImportantFolder(folderDataList);
        }
        store.release();
      } else {
        await this.initFolders();
      }
    }
    return this._folderList;
  }
  // 获取文件夹列表
  async getFolderList(parent: string): Promise<FolderData[]> {
    const folderList = await this.getAllFolderList();
    return folderList.filter(fd => fd.parent == parent) || [];
  }

  async deleteFolder(folderName: string): Promise<void> {
    const store = this.getStore();
    if(store.hasFeature(StoreFeature.Folder)) {
      await store.deleteFolder(folderName);
      this.syncFolder(store);
    }
    else {
      let folders = await this.getAllFolderList();
      let newFolders = folders.filter((item)=>{
        return item.fullName != folderName;
      })
      //更新缓存.
      this._folderList = newFolders;
      this._storage.setFolderList(newFolders);
    }
    store.release();
  }

  async createSubFolder(folderName: string, parent: string): Promise<void> {
    const store = this.getStore();
    if(store.hasFeature(StoreFeature.Folder)) {
      await store.createSubFolder(folderName, parent);
      this.syncFolder(store);
    }
    else {
      let folders = await this.getAllFolderList();
      //确保fullName不以/开头.
      let fullName = parent.length > 0 ? `${parent}/${folderName}` : `${folderName}`
      let newFolder:FolderData = {
        name: folderName,
        fullName: fullName,
        type: FolderType.other,
        parent: parent,
        mailCount: 0,
        unreadCount: 0
      };
      folders.push(newFolder);
      await this._storage.setFolderList(folders);
    }
    store.release();
  }

  async renameFolder(folderName: string, newName: string): Promise<void> {
    const store = this.getStore();
    if(store.hasFeature(StoreFeature.Folder)) {
      await store.renameFolder(folderName, newName);
      this.syncFolder(store);
    }
    else {
      let folders = await this.getAllFolderList();
      let newFolders = folders.map((item)=>{
        if(item.fullName == folderName) {
          item.fullName = newName;
        }
        return item;
      })
      this._storage.setFolderList(newFolders);
    }
    store.release();
  }

  // 检查配置是否正确
  check(): Promise<void> {
    const store = this.getStore();
    return store.check().then((): void => store.release()).catch(e => {
      store.release();
      throw e;
    });
  }
  // 获取支持的功能，参考StoreFeature的定义。目前主要是区分IMAP和POP3协议的功能
  supportedFeatures(): StoreFeature[] {
    return [
      StoreFeature.Folder,
      StoreFeature.VirtualFolder,
      StoreFeature.MailPart,
      StoreFeature.MailAttribute,
      StoreFeature.NeedToSync,
    ];
  }

  // 是否支持某个功能
  hasFeature(feature: StoreFeature): boolean {
    return this.supportedFeatures().includes(feature);
  }

  async getMail(folderFullName: string, mailId: string): Promise<IBuffer> {
    const store = this.getStore();
    const b = await store.getMail(folderFullName, mailId);
    store.release();
    return b
  }

  getMailPartContent(
    folderFullName: string,
    mailId: string,
    partId: string
  ): Promise<IBuffer> {
    return this._storage.getMailPartContent(folderFullName, mailId, partId).catch(async err => {
      logger.info(`no local cache for mail ${folderFullName} ${mailId}`, err)
      const store = this.getStore();
      const mail = await store.getMail(folderFullName, mailId);
      store.release();
      logger.trace("getMailPartContent add mail", mailId, partId);
      await this._storage.addMail(folderFullName, mailId, mail);
      // debug
      const mb = await this._storage.getMailBasic(folderFullName, mailId);
      logger.trace(mb.structure);
      // end debug
      return this._storage.getMailPartContent(folderFullName, mailId, partId).catch((err: unknown) => {
        logger.trace(folderFullName, mailId, partId, err);
        throw err;
      });
    })
  }

  async getMailBasic(
    folderFullName: string,
    mailId: string
  ): Promise<MailBasic> {
    logger.trace("getMailBasic", folderFullName, mailId)
    const mailBasic = await this._storage.getMailBasic(folderFullName, mailId);
    if (mailBasic) {
      logger.trace("getMailBasic storage", mailBasic);
      return mailBasic;
    } else {
      logger.trace("getMailBasic storage no data")
      const store = this.getStore();
      const mailData = await store.getMailBasic(folderFullName, mailId);
      store.release();
      logger.trace("getMailBasic add basic ")
      this._storage.addMailBasicList(folderFullName, [mailData])
      return mailData;
    }
  }

  async getMailIndex(
    folderFullName: string,
    mailId: string,
    order: Order
  ): Promise<number> {
    return this._storage.getMailIndex(folderFullName, mailId, order);
  }

  // 设置邮件的属性，返回设置后的属性列表
  // modifyType: "+"表示添加属性，"-"表示删除属性，""表示替换属性
  async setMailAttributes(
    folderFullName: string,
    mailId: string,
    attributes: MailAttribute[],
    modifyType: "+" | "-" | ""
  ): Promise<MailAttribute[]> {
    const store = this.getStore();
    if (store.hasFeature(StoreFeature.MailAttribute)) {
      const res = await store.setMailAttributes(
        folderFullName,
        mailId,
        attributes,
        modifyType
      ).catch(err => {
        //TODO 需要区分是什么原因导致的设置失败,正常情况下失败,需要操作数据库吗?
        //TODO 本地才有的邮件,需要操作数据库.
        countLogger.warn("set mail attr failed");
        // return attributes;
      });
      store.release();
      countLogger.trace(`[store set attr][end] [${JSON.stringify(res)}]`)
      let resDb = await this._storage.setMailAttributes(mailId,folderFullName,attributes,modifyType)
      // let mailData = await this._storage.getMailBasic(folderFullName, mailId);
      // mailData.attributes = res;
      countLogger.trace(`[storage set attr] [end]`)
      // await this._storage.addMailBasicList(folderFullName, [mailData]);
      return resDb;
    }
    else {
      //pop3
      store.release();
      let res = await this._storage.setMailAttributes(mailId,folderFullName,attributes,modifyType);
      let localFd = await this._storage.getFolderInfo(folderFullName);
      let fd =  this._folderList.find((item)=>{
        return item.fullName == folderFullName;
      });
      fd.unreadCount = localFd.unreadCount;
      fd.mailCount = localFd.mailCount;
      await this._storage.setFolderInfo(fd);
      return res;
    }
  }

  // 文件夹相关操作，需要支持StoreFeature.Folder才可以使用。
  // 标准协议里面，IMAP支持，POP3不支持

  // 获取文件夹信息，参考FolderData的定义
  // TODO: 改变一个邮件的未读状态后立即获取未读数,服务器返回的未读数可能不对.
  async getFolderInfo(folderName: string): Promise<FolderData> {
    if (this.getStore().hasFeature(StoreFeature.Folder)) {
      let fd: FolderData;
      if (folderName == IMPORTANT_FOLDER_NAME) {
        fd = await this._storage.getFolderInfo(folderName)
        countLogger.trace(`[SyncStore/getFolderInfo] [db folder info ${JSON.stringify(fd, ["name", "unreadCount"])}]`)
      }
      else {
        //mailReady之后,把整个操作以数据库为准,只有同步时以服务器为准.
        // if(this._folderList && this._folderList.length > 0) {
        //     await this._storage
        // }
          fd = await this._storage.getFolderInfo(folderName);
          countLogger.trace(`[SyncStore/getFolderInfo] [db folder info ${JSON.stringify(fd, ["name", "unreadCount"])}]`)
        // }
        // else {
        //   fd = await this._store.getFolderInfo(folderName);
        //   countLogger.trace(`[SyncStore/getFolderInfo] [server folder info ${JSON.stringify(fd, ["name", "unreadCount"])}]`)
        //   await this._storage.setFolderInfo(fd);
        // }
      }
         return fd;
      // }
      // else {
      //   const store = this.getStore();
      //   return store.getFolderInfo(folderName);
      // }
      // const folderList = await this.getAllFolderList();
      // const fd = folderList.find(fd => fd.fullName == folderName);
      // if (fd) {
      //   return fd;
      // } else {
      //   const store = this.getStore();
      //   return store.getFolderInfo(folderName);
      // }
    }
    else {
      return this._storage.getFolderInfo(folderName);
    }
  }
  // 打开文件夹，文件夹需要打开之后才可以读取邮件
  // 对应IMAP的select指令，POP3不需要打开
  async openFolder(folderName: string): Promise<FolderData> {
    if (folderName == IMPORTANT_FOLDER_NAME) {
      return {
        fullName: IMPORTANT_FOLDER_NAME,
        name: IMPORTANT_FOLDER_NAME,
        mailCount: 0,
        unreadCount: 0,
        recent: 0
      }
    }
    const store = this.getStore();
    this._currentFolder = folderName;
    if (store.hasFeature(StoreFeature.Folder)) {
      const fd = await store.openFolder(folderName);
      store.release();
      return fd;
    }
    else {
      store.release();
      let fd =  this._folderList.find((item)=>{
        return item.fullName == folderName
      });
      return fd;
    }

  }
  // 关闭文件夹，关闭之后就不能读取邮件了
  // 对应IMAP的close指令，POP3不需要关闭
  async closeFolder(folderName: string): Promise<void> {
    const store = this.getStore();
    await store.closeFolder(folderName);
    store.release();
    this._currentFolder = "";
  }
  // 判断文件夹是否打开
  isFolderOpen(folderName: string): boolean {
    if (folderName == IMPORTANT_FOLDER_NAME) {
      return true;
    }
    const isOpened = this.getStore().isFolderOpen(folderName);
    if (!isOpened) {
      this._currentFolder = "";
    }
    return isOpened;
  }

  async moveMail(fromFolder: string, mailId: string, folderName: string): Promise<string> {
    logger.debug("moveMail", fromFolder, mailId, folderName);
    let store = this.getStore();
    if (store.hasFeature(StoreFeature.MailAttribute)) {
      logger.debug(`[__imap][sync imap end fromFolder, mailId, folderName]`);
      const newMailId = await store.moveMail(fromFolder, mailId, folderName);
      store.release();
      logger.debug("moveMail imap end", fromFolder, mailId, folderName);
      await this._storage.moveMail(fromFolder, mailId, folderName, newMailId);
      logger.debug("moveMail imap end", fromFolder, mailId, folderName);
      return newMailId;
    }
    else {
      await this._storage.moveMail(fromFolder, mailId, folderName, mailId);

      //更新src文件夹数据.
      {
        let localFd = await this._storage.getFolderInfo(fromFolder);
        let fd = this._folderList.find((item) => {
          return item.fullName == fromFolder;
        });
        fd.unreadCount = localFd.unreadCount;
        fd.mailCount = localFd.mailCount;
        await this._storage.setFolderInfo(fd);
      }

      //更新dst文件夹数据.
      {
        let localFd = await this._storage.getFolderInfo(folderName);
        let fd = this._folderList.find((item) => {
          return item.fullName == folderName;
        });
        fd.unreadCount = localFd.unreadCount;
        fd.mailCount = localFd.mailCount;
        await this._storage.setFolderInfo(fd);
      }
      logger.debug("moveMail pop3 end", fromFolder, mailId, folderName);
      return mailId;
    }
  }

  async copyMail(fromFolder: string, mailId: string, folderName: string): Promise<string> {
    const store = this.getStore();
    const newMailId = await store.copyMail(fromFolder, mailId, folderName);
    store.release();
    this._storage.copyMail(fromFolder, mailId, folderName, newMailId);
    return newMailId;
  }

  async addMail(mail: string, folderName: string): Promise<string> {
    const store = this.getStore();
    let newMailId = "";
    const buff = this._bufferCreator.createBuffer({})
    buff.end(mail);
    if(store.hasFeature(StoreFeature.Folder)) {
      newMailId = await store.addMail(mail, folderName);
      store.release();
    }
    else {
      newMailId = util.generateRandomUUID();
    }
    await this._storage.addMail(folderName, newMailId, buff);
    return newMailId;
  }

  async deleteMail(fromFolder: string, mailId: string): Promise<void> {
    const store = this.getStore();
    if(store.hasFeature(StoreFeature.Folder)) {
      await store.deleteMail(fromFolder, mailId)
      await this._storage.deleteMail(fromFolder, mailId);
    }
    else {
      try {
        await store.getFolderInfo(INBOX);
        await store.deleteMail(fromFolder, mailId)
      }
      catch(e:unknown) {
        logger.warn(`failed to delete mail with id ${mailId} from ${fromFolder} from server`);
      }
      await this._storage.deleteMail(fromFolder, mailId);
    }
    store.release();
  }

  searchMail(query: Query): Promise<string[]> {
    return this._storage.searchMail(query);
  }
  filterMail(filter: Filter): Promise<Map<string, string[]>> {
    return this._storage.filterMail(filter);
  }

  on(
    event: "new-mail",
    handler: (folderFullName: string, mailIdList: string[]) => void
  ): void;
  on(event: string, handler: Function): void {
    logger.debug("register event", event);
    this._events.on(event, handler);
  }
}
